home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 37 / Amiga Format CD37 (1999-02-16)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-03].iso / -screenplay- / shareware / invasionforce / source / sound.c < prev    next >
C/C++ Source or Header  |  1999-01-09  |  10KB  |  352 lines

  1. /****************************   Sound.c   *********************************
  2.  
  3.     Sound is copyright (c) 1988 by Richard Lee Stockton, 21305 60th Ave W.,
  4. Mountlake Terrace, Washington 98043, 206/776-1253(voice), but may be freely
  5. distributed as long as no profit is made from its distribution or sale
  6. without my written permission. I call this concept 'FreeWare', you can
  7. call it whatcha want.
  8.  
  9. Hacked to death by Alan Bland, bears little resemblance to the original
  10. sound.c.
  11.  
  12. Extensively modified by Tony Belding for use with linked samples.
  13.  
  14. **************************************************************************/
  15.  
  16. #include <exec/types.h>
  17. #include <exec/memory.h>
  18. #include <libraries/dosextens.h>
  19. #include <devices/audio.h>
  20. #include <string.h>
  21.  
  22. #include <proto/exec.h>
  23.  
  24. #include "Sound.H"
  25. #include "sound_protos.h"
  26. #include "main_menu_protos.h"  /* for print() prototype */
  27. #include "Utils_protos.h"      /* for FLength() */
  28.  
  29. #define BUFSIZE 1024L
  30.  
  31. /* This array defines all the possible sounds */
  32.  
  33. struct SoundData sdata[MAX_SOUNDS];
  34.  
  35. struct IOAudio  *sound[4] = {NULL,NULL,NULL,NULL};
  36. UBYTE   sunit[4]={12,10,5,3};
  37. BOOL    device_open=FALSE;
  38.  
  39. BOOL toggle=FALSE;
  40. unsigned short playflags=0;
  41.  
  42. /*
  43.    The flag value "device_open" tracks the status of the audio
  44.    device.  This can also be used by the application to determine
  45.    whether the audio channels were successfully opened.
  46. */
  47.  
  48. /*********** quit, give-up, go home, finish... Neatness counts! ******/
  49.  
  50. void freeSounds()
  51. {
  52.    short k;
  53.  
  54.    /*
  55.       The flag "device_open" is a kluge value which lets me know if
  56.       the device was ever successfully opened.  If it was, the first
  57.       order of business here is to close it.  If it was not opened,
  58.       however, trying to close it would GURU us!
  59.    */
  60.    if (device_open) {
  61.       if(sound[0]) {    /* This cleans up the audio device stuff */
  62.          for(k=3;k>(-1);k--)
  63.             if(sound[k])
  64.                AbortIO((struct IORequest *)sound[k]);
  65.  
  66.          if(sound[0]->ioa_Request.io_Device)
  67.             CloseDevice((struct IORequest *)sound[0]);
  68.          device_open = FALSE;
  69.       }
  70.  
  71.       for(k=3;k>(-1);k--) {
  72.          if(sound[k]->ioa_Request.io_Message.mn_ReplyPort)
  73.             DeletePort(sound[k]->ioa_Request.io_Message.mn_ReplyPort);
  74.       }
  75.  
  76.       for(k=3;k>(-1);k--) {
  77.          if(sound[k])
  78.             FreeMem(sound[k],(long)sizeof(struct IOAudio));
  79.       }
  80.       sound[0]=NULL;
  81.    }
  82.  
  83.    /* Unload all sounds. */
  84.    for (k=0; k<MAX_SOUNDS; k++)
  85.       if (sdata[k].iffraw) {
  86.          FreeVec(sdata[k].iffraw);
  87.          sdata[k].iffraw = NULL;
  88.       }
  89.  
  90.    return;
  91. }
  92.  
  93.  
  94. /*  Don't Allocate if Low Mem - by Bryce Nesbitt  */
  95. /* Aberations by RLS. 4096 should be fudge enough */
  96.  
  97. char *SafeAllocMem(size,flags)
  98. long size, flags;
  99. {
  100.    register char *p;
  101.  
  102.    if(p=(char *)AllocMem(size,flags))
  103.       if(AvailMem(MEMF_CHIP)<4096L)
  104.          { FreeMem(p,size);  return(NULL); }
  105.    return(p);
  106. }
  107.  
  108.  
  109. /******** pre-parses IFF data ********/
  110.  
  111.  
  112. /*
  113.    Load IFF-8SVX data from a file and pre-parse it.
  114.    The input "source" is the filename to read data from,
  115.    and the input "sd" is a pointer to the SoundData
  116.    structure that needs to be filled in..
  117. */
  118.  
  119. void loadSound(source, sd)
  120. char *source;
  121. struct SoundData *sd;
  122. {
  123.    long i, j, sstart;
  124.    char string[5];
  125.    char *raw=NULL;
  126.  
  127.    /* If there's a sound already loaded here, we'll unload it first. */
  128.    if (sd->iffraw) {
  129.       FreeVec(sd->iffraw);
  130.       sd->iffraw = NULL;
  131.    }
  132.  
  133.    /* Now do all the file-reading stuff. */
  134.    {
  135.       long flen;
  136.       BPTR infile;
  137.  
  138.       /* See if the file is present, and how big. */
  139.       flen = FLength(source);
  140.       if (flen<0)
  141.          return;  /* no file found */
  142.  
  143.       /* Allocate chip RAM for it. */
  144.       raw = AllocVec(flen,MEMF_CHIP);
  145.       if (raw==NULL)
  146.          return;  /* no chip RAM available for us */
  147.  
  148.       /* Read the file. */
  149.       infile = Open(source,MODE_OLDFILE);
  150.       if (infile==NULL)
  151.          return;  /* for some reason we couldn't open it */
  152.       if (Read(infile,raw,flen)!=flen) {
  153.          Close(infile);
  154.          return;  /* unable to read file correctly */
  155.       }
  156.       Close(infile);
  157.    }
  158.  
  159.    /* remember location of "raw" so it can be de-allocated later */
  160.    sd->iffraw = raw;
  161.  
  162.    /* Set defaults if not found in IFF file */
  163.    sd->stereo = FALSE;
  164.    sd->sactual = 0L;
  165.  
  166.    /* Check for and parse IFF data in first 256 bytes of file */
  167.    for(sstart=0L, sd->sps=0L, i=0L; i<252L; i+=4L) {
  168.       strncpy(string,raw+i,4);
  169.       string[4]=NULL;
  170.       if(!(strcmp(string,"VHDR"))) {    /* get samples per second */
  171.          for(j=0; j<(long)((UBYTE)raw[i+20]); j++)
  172.             sd->sps += 256L;
  173.          sd->sps += ((UBYTE)raw[i+21L]);
  174.       }
  175.       if(!(strcmp(string,"CHAN"))) {    /* Channel Assignment */
  176.          if((raw[i+7]==6)||(raw[i+11]==6))
  177.             sd->stereo = TRUE;
  178.       }
  179.       if(!(strcmp(string,"BODY"))) {    /* get size of sound data */
  180.          for(j=0; j<4; j++)
  181.             sd->sactual += (((UBYTE)raw[i+7L-j])<<(8*j));
  182.          sstart = i+8L;   i = 252L;
  183.       }
  184.  
  185.       /* set beginning of sample location */
  186.       sd->sbuffer = raw+sstart;
  187.    }
  188. }
  189.  
  190.  
  191. void initSoundMem()
  192. {
  193.    short  k;
  194.  
  195.    /* Allocate the needed device structures.  Ports and   */
  196.    /* Audio Request Structures do NOT require CHIP memory */
  197.    for(k=0;k<4;k++) {
  198.  
  199.       if(!(sound[k]=(struct IOAudio *)SafeAllocMem((long)sizeof(struct IOAudio),MEMF_CLEAR|MEMF_PUBLIC))) {
  200.          freeSounds();    /* No IOA Memory! */
  201.          return;
  202.       }
  203.    }
  204.    if(
  205.        (!(sound[0]->ioa_Request.io_Message.mn_ReplyPort =
  206.            (struct MsgPort *) CreatePort("Sound0",0L))) ||
  207.        (!(sound[1]->ioa_Request.io_Message.mn_ReplyPort =
  208.            (struct MsgPort *) CreatePort("Sound1",0L))) ||
  209.        (!(sound[2]->ioa_Request.io_Message.mn_ReplyPort =
  210.            (struct MsgPort *) CreatePort("Sound2",0L))) ||
  211.        (!(sound[3]->ioa_Request.io_Message.mn_ReplyPort =
  212.            (struct MsgPort *) CreatePort("Sound3",0L))) ) {
  213.                 freeSounds();  /* No Port Memory! */
  214.                 return;
  215.    }
  216.  
  217.    /* Open Audio using the first IOAudio as the 'initializer' request */
  218.    sound[0]->ioa_Request.io_Message.mn_Node.ln_Pri = 20;
  219.    sound[0]->ioa_Data   = &sunit[0];
  220.    sound[0]->ioa_Length = 4L;
  221.    if((OpenDevice(AUDIONAME,0L,(struct IORequest *)sound[0],0L))!=NULL) {
  222.       freeSounds();  /* Unable to open audio device. */
  223.       return;
  224.    }
  225.    device_open = TRUE;
  226.  
  227.    /* Set all IOAudios. */
  228.    for(k=0;k<4;k++) {
  229.       sound[k]->ioa_Request.io_Message.mn_Node.ln_Pri = 20;
  230.       sound[k]->ioa_Request.io_Command = CMD_WRITE;
  231.       sound[k]->ioa_Request.io_Flags   = ADIOF_PERVOL;
  232.  
  233.       /* Note copies of Device & AllocKey from initializer. */
  234.       sound[k]->ioa_Request.io_Device  = sound[0]->ioa_Request.io_Device;
  235.       sound[k]->ioa_AllocKey  = sound[0]->ioa_AllocKey;
  236.  
  237.       /* One time through this BUFSIZE (or smaller) part of the whole */
  238.       sound[k]->ioa_Cycles = 1L;
  239.    }
  240.  
  241.    /* The compiler wants 'Unit' to be a structure, we just want to mask */
  242.    /* into the allocated left/right channels. left=1 or 8, right=2 or 4 */
  243.    /*        ...zap! You're a Unit structure! Feel any different?       */
  244.  
  245.    for(k=2;k>(-1);k-=2) {
  246.       sound[k+1]->ioa_Request.io_Unit = (struct Unit *)
  247.          ((ULONG)(sound[0]->ioa_Request.io_Unit)&6L);
  248.       sound[k]->ioa_Request.io_Unit  = (struct Unit *)
  249.          ((ULONG)(sound[0]->ioa_Request.io_Unit)&9L);
  250.    }
  251. }
  252.  
  253.  
  254. /*****************  make a noise ******************/
  255. /*             volume range  0 to 64              */
  256.  
  257. void playSound(snum, volume)
  258. int snum, volume;
  259. {
  260.    LONG    dactual, dlength, remaining;
  261.    short   k;
  262.    int set;
  263.  
  264.    /* don't do sound if not loaded */
  265.    if (sdata[snum].iffraw==NULL || sdata[snum].sbuffer==NULL)
  266.       return;
  267.  
  268.    /* watch out for a volume of zero */
  269.    if (volume==0)
  270.       return;
  271.  
  272.    /* if device was never successfully opened, abort */
  273.    if (device_open==FALSE)
  274.       return;
  275.  
  276.    /*
  277.       Decide which channels to use for this sound.
  278.       A sound always uses two channels, one left and one right, no matter
  279.       if it's mono or stereo.  If it's mono, it just plays the same sound
  280.       on both channels.  The program tries to alternate between the two sets
  281.       of left-right channels so sounds don't "stomp" upon one another.
  282.    */
  283.    if (toggle) {
  284.       set = 0;
  285.       toggle = FALSE;
  286.    } else {
  287.       set = 2;
  288.       toggle = TRUE;
  289.    }
  290.  
  291.    for (k=set; k<=(set+1); k++) {
  292.       /* 3579547 divided by 55 = 65083, nearly the maximum Period (65535) */
  293.       sound[k]->ioa_Period = 3579547L/sdata[snum].sps;
  294.  
  295.       /* set volume level */
  296.       sound[k]->ioa_Volume = (long)volume;
  297.    }
  298.  
  299.    /* If in STEREO, split file. If in MONO, 'b' buffers use 'a' data */
  300.    if(sdata[snum].stereo)
  301.       remaining = (sdata[snum].sactual/2L)-(sdata[snum].sactual&1L);
  302.    else {
  303.       remaining = sdata[snum].sactual;
  304.       sound[set]->ioa_Data = sdata[snum].sbuffer;
  305.       sound[set+1]->ioa_Data = sdata[snum].sbuffer;
  306.    }
  307.  
  308.    /* dactual is the length of one channel's complete data */
  309.    dactual = remaining;
  310.  
  311.    /* be CERTAIN ioa_Length is an even number & set datalength */
  312.    dlength = remaining;   dlength -= (dlength&1L);
  313.  
  314.    /* Left and Right Lengths are the same, no matter what! */
  315.    sound[set]->ioa_Length = sound[set+1]->ioa_Length = dlength;
  316.  
  317.    /* make sure there's not already a sound playing on these channels */
  318.    if (playflags & (1<<set)) {
  319.       WaitPort(sound[set]->ioa_Request.io_Message.mn_ReplyPort);
  320.       (void)GetMsg(sound[set]->ioa_Request.io_Message.mn_ReplyPort);
  321.       playflags &= ~(1<<set);
  322.    }
  323.    if (playflags & (1<<(set+1))) {
  324.       WaitPort(sound[set+1]->ioa_Request.io_Message.mn_ReplyPort);
  325.       (void)GetMsg(sound[set+1]->ioa_Request.io_Message.mn_ReplyPort);
  326.       playflags &= ~(1<<(set+1));
  327.    }
  328.  
  329.    /* Start one set of Left/Right Channels. */
  330.    BeginIO((struct IORequest *)sound[set]);
  331.    BeginIO((struct IORequest *)sound[set+1]);
  332.    playflags |= (1<<set);
  333.    playflags |= (1<<(set+1));
  334. }
  335.  
  336.  
  337. /******** initialize everything ********/
  338.  
  339. void initSounds()
  340. {
  341.    int k=0;
  342.  
  343.    /* Load 'em up! */
  344.    for (;k<MAX_SOUNDS;k++)
  345.       loadSound(current_sound[k],&sdata[k]);
  346.  
  347.    /* Setup chip buffers and I/O structures */
  348.    initSoundMem();
  349. }
  350.  
  351. /* END OF LISTING */
  352.